#!/bin/sh

. "$SPEC_PATH/abstract/metrics"
. "$SPEC_PATH/abstract/dbops-restart"

e2e_test_extra_hash() {
  "$SHELL" "$PROJECT_PATH/stackgres-k8s/ci/build/build-functions.sh" path_hash \
    "$(realpath --relative-to "$PROJECT_PATH" "$SPEC_PATH/abstract/metrics")"
  "$SHELL" "$PROJECT_PATH/stackgres-k8s/ci/build/build-functions.sh" path_hash \
    "$(realpath --relative-to "$PROJECT_PATH" "$SPEC_PATH/abstract/dbops-restart")"
}

e2e_test_install() {
  install_minio

  PRIMARY_CLUSTER_NAME="$(get_sgcluster_name "primary-$SPEC_NAME")"
  create_or_replace_cluster "$PRIMARY_CLUSTER_NAME" "$CLUSTER_NAMESPACE" "1"
  wait_cluster "$PRIMARY_CLUSTER_NAME" "$CLUSTER_NAMESPACE"
  create_or_replace_cluster "$CLUSTER_NAME" "$CLUSTER_NAMESPACE" "2" \
    --set configurations.create=false \
    --set instanceProfiles=null \
    --set-string cluster.replicateFrom.instance.sgCluster="$PRIMARY_CLUSTER_NAME"
  WAIT_CLUSTER_BOOTSTRAP_ONLY=true wait_cluster "$CLUSTER_NAME" "$CLUSTER_NAMESPACE"

  deploy_curl_pod "$CLUSTER_NAMESPACE"

  wait_pods_running "$CLUSTER_NAMESPACE" "5"
}

e2e_test() {
  run_test "Checking that standby is working" check_standby_is_working

  run_test "Checking that metrics are exported" check_metrics

  run_test "Checking that standby can be converted to primary" check_standby_can_be_converted_to_primary

  run_test "Checking that primary can be converted to standby" check_primary_can_be_converted_to_standby

  run_test "Checking that backup configuration is propagated to standby" check_backup_config_is_propagated_to_standby

  run_test "Checking that standby can be restarted" check_restart_standby
}

check_standby_is_working() {
  check_connectivity -i 0

  local SYNCHRONOUS_STANDBY_NAMES
  SYNCHRONOUS_STANDBY_NAMES="$(kubectl exec -n "$CLUSTER_NAMESPACE" "$CLUSTER_NAME-0" -c postgres-util -- \
    psql -q -At -c 'SHOW synchronous_standby_names')"
  if echo "$SYNCHRONOUS_STANDBY_NAMES" | grep -q '^$'
  then
    success "async replication is set for leader"
  else
    fail "async replication is not set for leader"
  fi

  local RESULT EXIT_CODE
  try_function run_query -p 5432 -h "$CLUSTER_NAME" -i 1 -q "CREATE DATABASE test;"
  if "$RESULT"
  then
    fail "It should not be possible to create a database in the leader node of the standby cluster"
  else
    success "It is not possible to create a database in the leader node of the standby cluster" 
  fi

  check_service_connectivity -i 0 -h "$CLUSTER_NAME-replicas"
  try_function run_query -p 5432 -i 0 -h "$CLUSTER_NAME-replicas" -q "CREATE TABLE fibonacci(num integer);" > "${LOG_PATH}/test1.log"
  if "$RESULT"
  then
    fail "It's possible to create a table in the replica node"
  else
    success "Good it is not possible to create a table in the replica node" 
  fi

  run_query -c "primary-$CLUSTER_NAME" -p 5432 -h "primary-$CLUSTER_NAME" -i 0 -q "CREATE DATABASE test;"
  run_query -c "primary-$CLUSTER_NAME" -p 5432 -h "primary-$CLUSTER_NAME" -i 0 -q "CREATE TABLE fibonacci(num integer);" -d test
  run_query -c "primary-$CLUSTER_NAME" -p 5432 -h "primary-$CLUSTER_NAME" -i 0 -q "INSERT INTO fibonacci(num) VALUES (1);" -d test
  run_query -c "primary-$CLUSTER_NAME" -p 5432 -h "primary-$CLUSTER_NAME" -i 0 -q "INSERT INTO fibonacci(num) VALUES (2);" -d test
  run_query -c "primary-$CLUSTER_NAME" -p 5432 -h "primary-$CLUSTER_NAME" -i 0 -q "INSERT INTO fibonacci(num) VALUES (3);" -d test

  PRIMARY_RESPONSE="$(run_query -c "primary-$CLUSTER_NAME" -p 5432 -i 0 -h "primary-$CLUSTER_NAME" -q "SELECT num FROM fibonacci ORDER BY num;" -d "test")"

  if [ "$(echo "$PRIMARY_RESPONSE" | tr -d '\n')" = "123" ]
  then
    success "inserts on the primary where successful."
  else
    fail "inserts on the primary where not successful."
  fi

  try_function wait_until eval '
    STANDBY_RESPONSE="$(run_query -p 5432 -i 0 -h "$CLUSTER_NAME" -q "SELECT num FROM fibonacci ORDER BY num;" -d "test")"
    [ "$(echo "$PRIMARY_RESPONSE" | tr -d "\n")" = "$(echo "$STANDBY_RESPONSE" | tr -d "\n")" ]
    '
  if "$RESULT"
  then
    success "standby replication is working"
  else
    fail "standby replication is not working. The records don't match between primary and standby for the fibonacci table"
  fi

  try_function wait_until eval '
    REPLICA_RESPONSE="$(run_query -p 5432 -i 0 -h "$CLUSTER_NAME-replicas" -q "SELECT num FROM fibonacci ORDER BY num;" -d "test")"
    [ "$(echo "$PRIMARY_RESPONSE" | tr -d "\n")" = "$(echo "$REPLICA_RESPONSE" | tr -d "\n")" ]
    '
  if "$RESULT"
  then
    success "replication is working"
  else
    fail "replication is not working. The records don't match between primary and replica for the fibonacci table"
  fi
}

check_standby_can_be_converted_to_primary() {
  create_or_replace_cluster "$CLUSTER_NAME" "$CLUSTER_NAMESPACE" "2" \
    --reset-values \
    --set configurations.create=false \
    --set instanceProfiles=null \
    --set cluster.replicateFrom=null

  local RESULT EXIT_CODE
  try_function wait_until run_query -p 5432 -h "$CLUSTER_NAME" -i 1 -q "CREATE DATABASE test2;"
  if "$RESULT"
  then
    success "The leader node of the standby cluster was converted to a primary" 
  else
    fail "The leader node of the standby cluster was not converted to a primary"
  fi

  run_query -p 5432 -h "$CLUSTER_NAME" -i 0 -q "CREATE TABLE fibonacci(num integer);" -d test2
  run_query -p 5432 -h "$CLUSTER_NAME" -i 0 -q "INSERT INTO fibonacci(num) VALUES (1);" -d test2
  run_query -p 5432 -h "$CLUSTER_NAME" -i 0 -q "INSERT INTO fibonacci(num) VALUES (2);" -d test2
  run_query -p 5432 -h "$CLUSTER_NAME" -i 0 -q "INSERT INTO fibonacci(num) VALUES (3);" -d test2

  PRIMARY_RESPONSE="$(run_query -p 5432 -i 0 -h "$CLUSTER_NAME" -q "SELECT num FROM fibonacci ORDER BY num;" -d "test2")"

  if [ "$(echo "$PRIMARY_RESPONSE" | tr -d '\n')" = "123" ]
  then
    success "inserts on the primary where successful."
  else
    fail "inserts on the primary where not successful."
  fi

  try_function wait_until eval '
    REPLICA_RESPONSE="$(run_query -p 5432 -i 0 -h "$CLUSTER_NAME-replicas" -q "SELECT num FROM fibonacci ORDER BY num;" -d "test2")"
    [ "$(echo "$PRIMARY_RESPONSE" | tr -d "\n")" = "$(echo "$REPLICA_RESPONSE" | tr -d "\n")" ]
    '
  if "$RESULT"
  then
    success "replication is working"
  else
    fail "replication is not working. The records don't match between primary and replica for the fibonacci table"
  fi
}

check_primary_can_be_converted_to_standby() {
  create_or_replace_cluster "$CLUSTER_NAME" "$CLUSTER_NAMESPACE" "2" \
    --reset-values \
    --set configurations.create=false \
    --set instanceProfiles=null \
    --set-string cluster.replicateFrom.instance.sgCluster="$PRIMARY_CLUSTER_NAME"

  local RESULT EXIT_CODE
  try_function wait_until run_query -p 5432 -h "$CLUSTER_NAME" -i 1 -q "$(cat << 'EOF'
DO $$BEGIN
  IF EXISTS (SELECT * FROM pg_database WHERE datname = 'test2')
  THEN
    RAISE EXCEPTION 'Database test2 does exists';
  END IF;
END$$;
EOF
    )"
  if "$RESULT"
  then
    success "The leader node of the standby cluster is following the primary cluster" 
  else
    fail "The leader node of the standby cluster is not following the primary cluster"
  fi

  local RESULT EXIT_CODE
  try_function run_query -p 5432 -h "$CLUSTER_NAME" -i 1 -q "CREATE DATABASE test2;"
  if "$RESULT"
  then
    fail "It should not be possible to create a database in the leader node of the standby cluster"
  else
    success "It is not possible to create a database in the leader node of the standby cluster" 
  fi

  check_service_connectivity -i 0 -h "$CLUSTER_NAME-replicas"
  try_function run_query -p 5432 -i 0 -h "$CLUSTER_NAME-replicas" -q "CREATE TABLE fibonacci(num integer);" > "${LOG_PATH}/test1.log"
  if "$RESULT"
  then
    fail "It's possible to create a table in the replica node"
  else
    success "Good it is not possible to create a table in the replica node" 
  fi

  run_query -c "primary-$CLUSTER_NAME" -p 5432 -h "primary-$CLUSTER_NAME" -i 0 -q "CREATE DATABASE test2;"
  run_query -c "primary-$CLUSTER_NAME" -p 5432 -h "primary-$CLUSTER_NAME" -i 0 -q "CREATE TABLE fibonacci(num integer);" -d test2
  run_query -c "primary-$CLUSTER_NAME" -p 5432 -h "primary-$CLUSTER_NAME" -i 0 -q "INSERT INTO fibonacci(num) VALUES (1);" -d test2
  run_query -c "primary-$CLUSTER_NAME" -p 5432 -h "primary-$CLUSTER_NAME" -i 0 -q "INSERT INTO fibonacci(num) VALUES (2);" -d test2
  run_query -c "primary-$CLUSTER_NAME" -p 5432 -h "primary-$CLUSTER_NAME" -i 0 -q "INSERT INTO fibonacci(num) VALUES (3);" -d test2

  PRIMARY_RESPONSE="$(run_query -c "primary-$CLUSTER_NAME" -p 5432 -i 0 -h "primary-$CLUSTER_NAME" -q "SELECT num FROM fibonacci ORDER BY num;" -d "test2")"

  if [ "$(echo "$PRIMARY_RESPONSE" | tr -d '\n')" = "123" ]
  then
    success "inserts on the primary where successful."
  else
    fail "inserts on the primary where not successful."
  fi

  try_function wait_until eval '
    STANDBY_RESPONSE="$(run_query -p 5432 -i 0 -h "$CLUSTER_NAME" -q "SELECT num FROM fibonacci ORDER BY num;" -d "test2")"
    [ "$(echo "$PRIMARY_RESPONSE" | tr -d "\n")" = "$(echo "$STANDBY_RESPONSE" | tr -d "\n")" ]
    '
  if "$RESULT"
  then
    success "standby replication is working"
  else
    fail "standby replication is not working. The records don't match between primary and standby for the fibonacci table"
  fi

  try_function wait_until eval '
    REPLICA_RESPONSE="$(run_query -p 5432 -i 0 -h "$CLUSTER_NAME-replicas" -q "SELECT num FROM fibonacci ORDER BY num;" -d "test2")"
    [ "$(echo "$PRIMARY_RESPONSE" | tr -d "\n")" = "$(echo "$REPLICA_RESPONSE" | tr -d "\n")" ]
    '
  if "$RESULT"
  then
    success "replication is working"
  else
    fail "replication is not working. The records don't match between primary and replica for the fibonacci table"
  fi
}

check_backup_config_is_propagated_to_standby() {
  create_or_replace_cluster "backupconf" "$CLUSTER_NAMESPACE" "1" \
    --set configurations.objectstorage.create=true \
    --set cluster.create=false \
    --set configurations.postgresconfig.create=false \
    --set configurations.poolingconfig.create=false \
    --set instanceProfiles=null \
    --set-string configurations.objectstorage.s3Compatible.bucket=stackgres \
    --set-string configurations.objectstorage.s3Compatible.awsCredentials.secretKeySelectors.accessKeyId.name=standby-from-cluster-minio \
    --set-string configurations.objectstorage.s3Compatible.awsCredentials.secretKeySelectors.accessKeyId.key=accesskey \
    --set-string configurations.objectstorage.s3Compatible.awsCredentials.secretKeySelectors.secretAccessKey.name=standby-from-cluster-minio \
    --set-string configurations.objectstorage.s3Compatible.awsCredentials.secretKeySelectors.secretAccessKey.key=secretkey \
    --set-string configurations.objectstorage.s3Compatible.region=k8s \
    --set configurations.objectstorage.s3Compatible.enablePathStyleAddressing=true \
    --set-string configurations.objectstorage.s3Compatible.endpoint=http://standby-from-cluster-minio:9000 \
    --set-string cluster.configurations.backups.sgObjectStorage=backupconf

  create_or_replace_cluster "$PRIMARY_CLUSTER_NAME" "$CLUSTER_NAMESPACE" "1" \
    --set configurations.objectstorage.create=false \
    --set cluster.configurations.backups.retention=2 \
    --set-string cluster.configurations.backups.cronSchedule='0 5 31 2 *' \
    --set-string cluster.configurations.backups.sgObjectStorage=backupconf

  try_function wait_until eval '
    STANDBY_RESPONSE="$(run_query -p 5432 -i 0 -h "$CLUSTER_NAME" -q "SHOW restore_command")"
    [ "" != "$(echo "$STANDBY_RESPONSE" | tr -d "\n")" ]
    '
  if "$RESULT"
  then
    success "standby replication is using restore_command"
  else
    fail "standby replication is not using restore_command"
  fi
}

check_restart_standby() {
  trigger_cluster_require_restart
  DBOPS_NAME="$(get_sgdbops_name restart)"

  set_restarted_pods

  cat << EOF | kubectl create -f -
apiVersion: stackgres.io/v1
kind: SGDbOps
metadata:
  name: $DBOPS_NAME
  namespace: $CLUSTER_NAMESPACE
spec:
  sgCluster: $CLUSTER_NAME
  op: restart
  restart:
    method: InPlace
EOF

  check_restart_without_data
}